package uk.co.hs.web.security.filter;

import java.io.IOException;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;

import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.GenericFilterBean;

/**
 * WaffleNegotiateSecurityPostFilter.
 */
public class WaffleNegotiateSecurityPostFilter extends GenericFilterBean
{
  private AuthenticationManager mAuthenticationManager;
  private String mDefaultUrl;

  /**
   * @param aAuthenticationManager the authenticationManager to set
   */
  public void setAuthenticationManager(AuthenticationManager
                                       aAuthenticationManager)
  {
    mAuthenticationManager = aAuthenticationManager;
  }

  /**
   * @see javax.servlet.Filter
   *        #doFilter(javax.servlet.ServletRequest,
   *                  javax.servlet.ServletResponse, javax.servlet.FilterChain)
   * {@inheritDoc}
   */
  public void doFilter(ServletRequest aRequest, ServletResponse aResponse,
                       FilterChain aChain) throws IOException, ServletException
  {
    HttpServletRequest request = (HttpServletRequest) aRequest;
    HttpServletResponse response = (HttpServletResponse) aResponse;
    HttpSession session = request.getSession();

    Authentication waffleAuthentication
      = SecurityContextHolder.getContext().getAuthentication();

    Authentication previousWaffleAuth
      = (Authentication) session.getAttribute("UTILISOFT_WAFFLE_SSO_AUTH");

    if (waffleAuthentication != null
        && previousWaffleAuth != null
        && waffleAuthentication.getName().equals(previousWaffleAuth.getName()))
    {
      SecurityContextHolder.getContext().setAuthentication(
        (Authentication) session.getAttribute("UTILISOFT_SSO_AUTH"));
    }
    else if (waffleAuthentication != null)
    {
      try
      {
        String domainAndName = waffleAuthentication.getName();
        String name = null;
        if (domainAndName.contains("\\"))
        {
          name = domainAndName.substring(domainAndName.indexOf('\\') + 1);
        }
        else
        {
          name = domainAndName;
        }

        UsernamePasswordAuthenticationToken usernamePassword =
        new UsernamePasswordAuthenticationToken(name, waffleAuthentication.getCredentials());

        // Authenitcate the user with the authentication manager
        Authentication authentication = mAuthenticationManager.authenticate(usernamePassword);

        // Set the Authentication object with the valid authentication result
        SecurityContextHolder.getContext().setAuthentication(authentication);

        // Store in session so its not wiped by waffle
        session.setAttribute("UTILISOFT_SSO_AUTH", authentication);
        session.setAttribute("UTILISOFT_WAFFLE_SSO_AUTH", waffleAuthentication);

        if (request.getSession().isNew())
        {
          String[] splitURI = request.getRequestURI().split("/");

          if (splitURI.length >= 3)
          {
            response.sendRedirect("/" + splitURI[1] + mDefaultUrl);
          }
        }
      }
      catch (AuthenticationException failed)
      {
          if (logger.isInfoEnabled())
          {
              logger.info("Authentication request for user: "
                          + waffleAuthentication.getName() + " failed: "
                          + failed.toString());
          }
          System.out.println("AuthenticationException: " + failed.getMessage());
          failed.printStackTrace();
          throw failed;
      }
    }
    aChain.doFilter(aRequest, aResponse);
  }

  public void setDefaultUrl(String aDefaultUrl)
  {
    mDefaultUrl = aDefaultUrl;
  }
}
